#ifndef __list_h
#define __list_h

/**
 * @file list.h @ingroup sd
 *
 * @brief Generic list object. It is implemented as an array of doubly-linked
 * lists of iterators. The index within the array is computed by a efficient
 * list function.
 */

#include <stdio.h>

__BEGIN_DECLS

/**
 * This is the list object.
 */
typedef struct __list list_t;

struct __list_iter {
    void *data;
    struct __list *list;
    struct __list_iter *__next;
    struct __list_iter *__prev;
    int __foreach;
};

/**
 * This is the elementary container for storing data into the list object.
 */
typedef struct __list_iter list_iter_t;

/**
 * Signature of a "foreach" function.
 */
typedef unsigned int (*list_func_t)(void *a_data, void *a_userdata);

/**
 * Creates a list.
 * @param a_capacity initial number of preallocated iterators
 * @return the list object.
 */
extern list_t *list_new(size_t a_capacity);

/**
 * Destroys the list object.
 * @todo need a function parameter to destroy list elements.
 */
extern void list_delete(list_t *a_this);

/**
 * Adds the given_data at the head of the list.
 */
extern list_iter_t *list_prepend(list_t *a_this, void *a_data);

/**
 * Adds the given data at the tail of the list.
 */
extern list_iter_t *list_append(list_t *a_this, void *a_data);

/**
 * Looks for the iterator associated to the given data in the list object.
 * @param a_data the data to find
 * @return a pointer to the found iterator or NULL.
 */
extern list_iter_t *list_lookup(list_t *a_this, void *a_data);

/**
 * Looks for the iterator associated to the given data in the list object and
 * creates it if doesn't exist, using @c list_add().
 * @param a_data the data to find/add
 * @return a pointer to the found iterator or NULL.
 */
extern list_iter_t *list_look_add(list_t *a_this, void *a_data);

/**
 * Adds the given data into the list object. If the data already exists,
 * the associated iterator is returned.
 * @warning the element is added at the begining of the list.
 * @param a_data the data to add
 * @return a pointer to the created or found iterator.
 */
extern list_iter_t *list_add(list_t *a_this, void *a_data);

/**
 * Applies the given function to all list elements, starting from the
 * first one. As soon as the function returns a non-null value, the
 * given data is inserted in the list (before the element).
 * @param a_func the "sort" function.
 * @param a_data the data to add
 * @return a pointer to the created iterator.
 */
extern list_iter_t *list_sort_add(list_t *a_this, list_func_t a_func, void *a_data);

/**
 * Removes an iterator from the list object.
 * @param a_data the data associated to the iterator.
 */
extern int list_del(list_t *a_this, void *a_data);

/**
 * clears the list object.
 */
extern void list_clear(list_t *a_this);

/**
 * Calls \a a_func for each element of the list object, as long as \a a_func
 * returns 0.
 * @param a_func the "foreach" function.
 * @param a_data the user data passed to \a a_func.
 */
extern void list_foreach(list_t *a_this, list_func_t a_func, void *a_userdata);

/**
 * Calls \a a_func for each element of the list object, as long as \a a_func
 * returns 0.
 * Same as list_foreach but from tail to head of list.
 * @param a_func the "foreach" function.
 * @param a_data the user data passed to \a a_func.
 */
extern void list_foreach_r(list_t *a_this, list_func_t a_func, void *a_userdata);

/**
 * Gets the number of iterators.
 */
extern size_t list_get_nelem(list_t *a_this);

/**
 * Gets the iterator pointing to the first element of the list.
 */
extern list_iter_t *list_begin(list_t *a_this);

/**
 * Gets the past-the-last-element iterator of the list.
 */
extern list_iter_t *list_end(list_t *a_this);

/**
 * Gets the iterator pointing to the last element of the list.
 */
extern list_iter_t *list_begin_r(list_t *a_this);

/**
 * Gets the before-the-first-element iterator of the list.
 */
extern list_iter_t *list_end_r(list_t *a_this);

/**
 * Gets a pointer to the next iterator.
 */
extern list_iter_t *list_iter_next(list_iter_t *a_this);

/**
 * Gets a pointer to the previous iterator.
 */
extern list_iter_t *list_iter_prev(list_iter_t *a_this);

/**
 * Deletes the iterator from the list.
 */
extern void list_iter_del(list_iter_t *a_this);

/**
 * Creates a new iterator and inserts it before @a a_this.
 * @param a_data the data associated to the iterator.
 */
extern list_iter_t *list_iter_insert(list_iter_t *a_this, void *a_data);

__END_DECLS
#endif
